home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 7: Sunsite
/
Linux Cubed Series 7 - Sunsite Vol 1.iso
/
system
/
printing
/
magicfil.2
/
magicfilter-1.2.tar
/
magicfilter-1.2
/
parseconfig.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-15
|
9KB
|
429 lines
/*
* parseconfig.c
*
* Routine library for parsing the configuration file
*
* Copyright ⌐ 1995 H. Peter Anvin
*/
#include "magicfilter.h"
/*
* int getoffset(char *startpos, char **endpos)
*
* Returns the parsing offset (a decimal, octal or hex number, or "default").
* Returns the number, or one of the negative numbers
* MAG_DEFAULT ... is default
* MAG_COMMENT ... comment line
* MAG_ERR ... invalid offset
*
* *endpos is set to the first character after the offset, unless NULL
*/
int getoffset(char *p, char **endpos)
{
int offset = 0; /* So far */
enum { st_start, st_zero, st_oct, st_dec, st_hex, st_done } state = st_start;
#if DEBUG > 3
fprintf(stderr,"getoffset %s\n", p);
#endif
while ( isspace(*p) ) p++; /* Skip leading whitespace */
while ( state != st_done )
{
switch( state )
{
case st_start:
switch ( *p )
{
case '\b': /* Whitespace */
case '\t':
case '\n':
case '\v':
case '\f':
case '\r':
case ' ':
p++;
break;
case '#':
case '\0': /* Blank line counts as comment */
offset = MAG_COMMENT;
state = st_done;
break;
case '0':
state = st_zero;
p++;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
offset = *p - '0';
state = st_dec;
p++;
break;
case 'd':
if ( strncmp(p, "default", 7) )
{
offset = MAG_ERR;
}
else
{
p += 7;
offset = MAG_DEFAULT;
}
state = st_done;
break;
default:
offset = MAG_ERR;
state = st_done;
break;
}
break;
case st_zero:
if ( *p == 'x' || *p == 'X' )
{
state = st_hex;
p++;
break;
}
/* else fall through */
case st_oct:
if ( *p < '0' || *p > '7' )
{
state = st_done;
}
else
{
offset <<= 3;
offset += *(p++) - '0';
}
break;
case st_dec:
if ( *p < '0' || *p > '9' )
{
state = st_done;
}
else
{
offset *= 10;
offset += *(p++) - '0';
}
break;
case st_hex:
if ( *p >= '0' && *p <= '9' )
{
offset <<= 4;
offset += *(p++) - '0';
}
else if ( *p >= 'A' && *p <= 'F' )
{
offset <<= 4;
offset += *(p++) - 'A' + 10;
}
else if ( *p >= 'a' && *p <= 'f' )
{
offset <<= 4;
offset += *(p++) - 'a' + 10;
}
else
{
state = st_done;
}
}
}
if ( endpos )
*endpos = p; /* Where did we end? */
return offset;
}
/*
* int getmagic(char *startpos, char **endpos, char *magic, char *mask)
*
* Parse a magic string, returning the number of bytes in the magic string.
* Stores the endpoint in *endpos if requested. If magic and/or mask
* is NULL, do not store; used to count the number of characters in the
* magic/mask string.
*
* Each character in mask is either 0 for \? (don't care) or (char)-1 for
* any other (do care).
*
* If mask is set to the senitel value NO_WILD (a unique pointer value
* pointing to a bogus static string) the \? will not be interpreted
* as don't care; just as a regular escaped questionmark.
*
*/
char NO_WILD[1] = ""; /* Used as senitel value */
int getmagic(char *p, char **endpos, char *magic, char *mask)
{
int count = 0; /* Count of bytes */
int quote = 0; /* Quoted? */
int ch;
int wildcards = 1; /* Wildcards allowed by default */
enum { st_def, st_backsl, st_oct, st_hex, st_done } state = st_def;
#if DEBUG > 3
fprintf(stderr,"getmagic %s\n", p);
#endif
if ( mask == NO_WILD ) /* If wildcards forbidden */
{
mask = NULL; /* Don't store a mask */
wildcards = 0; /* Don't accept wildcards */
}
while ( isspace(*p) ) p++; /* Skip leading whitespace */
while ( state != st_done )
{
switch ( state )
{
case st_def:
switch ( *p )
{
case '\n': /* Unconditional whitespace */
case '\r':
case '\f':
case '\0':
if ( quote )
count = MAG_ERR;
state = st_done;
break;
case '\\': /* Backslash */
p++;
state = st_backsl;
break;
case '\"': /* Quote */
p++;
quote = !quote;
break;
case '\b': /* Whitespace */
case '\t':
case '\v':
case ' ':
if ( !quote )
{
state = st_done;
break;
}
/* else fall though */
default:
if ( magic ) *(magic++) = *p;
if ( mask ) *(mask++) = (char)(-1);
p++; count++;
break;
}
break;
case st_backsl: /* After backslash */
ch = -1;
switch ( *p )
{
case 'a':
ch = 7; /* Bell */
break;
case 'b':
ch = '\b'; /* Backspace */
break;
case 'e':
ch = 27; /* Escape */
break;
case 'f':
ch = '\f'; /* Form feed */
break;
case 'n':
ch = '\n'; /* Newline */
break;
case 'r':
ch = '\r'; /* Return */
break;
case 't':
ch = '\t'; /* Tab */
break;
case 'v':
ch = '\v'; /* Vtab */
break;
case 'x':
case 'X':
state = st_hex; /* Hex prefix */
ch = 0;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
state = st_oct; /* Octal prefix */
ch = *p - '0';
break;
case '?':
if ( wildcards )
{
if ( magic ) *(magic++) = (char)0; /* Ignore byte */
if ( mask ) *(mask++) = (char)0;
count++;
state = st_def;
break;
}
/* else fall through */
default:
ch = *p; /* Preserve character (e.g. " or \) */
break;
}
p++;
if ( state == st_backsl )
{
if ( magic ) *(magic++) = ch;
if ( mask ) *(mask++) = (char)(-1);
count++;
state = st_def;
}
break;
case st_oct:
if ( *p >= '0' && *p <='7' )
{
ch <<= 3;
ch += *(p++) - '0';
}
else
{
if ( magic ) *(magic++) = ch;
if ( mask ) *(mask++) = (char)(-1);
count++;
state = st_def; /* Do not advance p */
}
break;
case st_hex:
if ( *p >= '0' && *p <= '9' )
{
ch <<= 4;
ch += *(p++) - '0';
}
else if ( *p >= 'A' && *p <= 'F' )
{
ch <<= 4;
ch += *(p++) - 'A' + 10;
}
else if ( *p >= 'a' && *p <= 'f' )
{
ch <<= 4;
ch += *(p++) - 'a' + 10;
}
else
{
if ( magic ) *(magic++) = ch;
if ( mask ) *(mask++) = (char)(-1);
count++;
state = st_def; /* Do not advance p */
}
break;
}
}
if (endpos) *endpos = p;
return count;
}
/*
* enum actions getaction(char *pos, char **cmd)
*
* Reads the action proposed and returns:
*
* ACT_CAT ... output file raw
* ACT_DROP ... silently ignore
* ACT_REJECT ... mail user and complain
* ACT_FILTER ... run through once, then done
* ACT_PIPETHRU ... run through command, then feed back through filter
* ACT_ADDCR ... \n -> \r\n, \f -> \r\f
* ACT_PS ... same as ADDCR, but add Ctrl-D at end
* ACT_FFILTER ... same as FILTER, but use a temp file
* ACT_FPIPE ... same as PIPETHRU, but use a temp file
*
* If the command takes an argument, point cmd to it if non-NULL
*
* IMPORTANT: The matching algorithm is a bit simplistic. If any action
* is a proper prefix of any other action, the longer action must be first
* in the list.
*/
enum actions getaction(char *pos, char **cmd)
{
enum actions act;
static char *act_strs[] = { "cat", "ignore", "reject", "filter",
"pipe", "text", "postscript",
"ffilter", "fpipe", NULL };
char **act_str;
int i;
#if DEBUG > 3
fprintf(stderr,"getaction %s\n", pos);
#endif
while ( isspace(*pos) ) pos++; /* Ignore leading whitespace */
if ( ! *pos )
return ACT_ERR; /* Syntax error */
for ( act = ACT_CAT, act_str = act_strs ; *act_str ; act++, act_str++ )
if ( strncmp(pos, *act_str, i = strlen(*act_str)) == 0 )
{
pos += i;
break;
}
if ( ! *act_str )
{
#if DEBUG > 3
fprintf(stderr,"No match\n");
#endif
return ACT_ERR; /* Unknown action */
}
if ( *pos && !isspace(*pos) )
{
#if DEBUG > 3
fprintf(stderr,"Garbage at end: %s\n", pos);
#endif
return ACT_ERR; /* Garbage after action name */
}
if ( cmd )
{
while ( isspace(*pos) ) pos++; /* Skip leading whitespace again */
*cmd = pos;
}
return act;
}